package com.site.common.exception;

import com.site.common.R;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MaxUploadSizeExceededException;

import javax.servlet.ServletException;
import java.util.Optional;

/**
 * 全局异常
 * 启动应用后，被 @ExceptionHandler、@InitBinder、@ModelAttribute 注解的方法，都会作用在 被 @RequestMapping 注解的方法上。
 */
@RestControllerAdvice
public class GlobalControllerAdvice {

    private static Logger logger = LoggerFactory.getLogger(GlobalControllerAdvice.class);

    /**
     * 应用到所有@RequestMapping注解方法，在其执行之前初始化数据绑定器
     * @param binder
     */
    @InitBinder
    public void initBinder(WebDataBinder binder){}

    /**
     * 把值绑定到Model中，使全局@RequestMapping可以获取到该值
     * @param model
     * 在Model上设置的值，对于所有被 @RequestMapping 注解的方法中，都可以通过 ModelMap 获取 (ModelMap modelMap)，modelMap.get(key)
     */
    @ModelAttribute
    public void addAttributes(Model model){}

    /**
     * 参数异常 org.springframework.util.Assert 断言异常
     * @param e
     * @return
     */
    @ExceptionHandler(IllegalArgumentException.class)
    public R<String> handleIllegalArgumentException(IllegalArgumentException e){
        logger.error("参数异常,Assert -> {}",e);
        return R.error(e.getMessage());
    }

    /**
     * 参数异常
     * @param e
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public R<String> handleMethodArgumentException(MethodArgumentNotValidException e){
        logger.error("参数异常,{}",e);
        BindingResult bindingResult = e.getBindingResult();
        FieldError fieldError = bindingResult.getFieldError();
        return R.error(Optional.ofNullable(fieldError).map(FieldError::getDefaultMessage).orElse("参数异常"));
    }

    /**
     * 业务异常
     * @param e
     * @return
     */
    @ExceptionHandler(BusinessException.class)
    public R<String> handleBusinessException(BusinessException e){
        logger.error("业务异常,{}",e);
        return R.error(e.getCode(),e.getMessage());
    }

    /**
     * 系统异常
     * @param e
     * @return
     */
    @ExceptionHandler(Exception.class)
    public R<String> handleException(Exception e){
        if (e instanceof MaxUploadSizeExceededException){
            logger.error("上传异常：{}",e);
            return R.error("上传文件太大");
        }
        if (e instanceof ServletException){
            logger.error("请求类型异常：{},",e);
            return R.error("请求类型异常");
        }
        if (e instanceof HttpMessageNotReadableException){
            logger.error("请求体不正确：{},",e);
            return R.error("请求体为空或参数类型不正确");
        }
        logger.error("接口出现严重异常：{}",e);
        return R.error("系统异常");
    }
}
